package dosgi.core.hook;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Dictionary;
import java.util.concurrent.atomic.AtomicReference;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.hooks.service.EventListenerHook;
import org.osgi.framework.hooks.service.FindHook;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;

import dbconnector.service.IServiceRegisterManager;
import dosgi.core.util.DatabaseProxy;
import dosgi.core.util.LogHelper;

@SuppressWarnings("rawtypes")
public class HooksManager implements ManagedService {

	
	private LogService logger = LogHelper.getLogger();
	private static final String PROP_HOST = "hostIP";
	
	public static final String REMOTE_PROPERTY_KEY = "remote";
	public static final String REMOTE_PROPERTY_VALUE_TRUE = "true";
	public static final String PROXY_PROPERTY_KEY = "proxy";
	public static final String PROXY_PROPERTY_VALUE_TRUE = "true";
	
	private BundleContext context;
	private ChangeServiceHook changeServiceHook;
	private GetServiceHook getServiceHook;
	private DatabaseProxy databaseProxy;
	private AtomicReference<ServiceRegistration> changeServiceHookReference = new AtomicReference<ServiceRegistration>();
	private AtomicReference<ServiceRegistration> getServiceHookReference = new AtomicReference<ServiceRegistration>();
	
	private String hostIP;
	
	public HooksManager(BundleContext context) {
		super();
		this.context = context;
		this.databaseProxy = new DatabaseProxy();
	}
	
	public void setDatabase(IServiceRegisterManager databaseManager) {
		databaseProxy.setDatabaseManager(databaseManager);
	}
	
	public void setQueueName(String queueName) {
		databaseProxy.setQueueName(queueName);
	}

	/**
	 * This method is invoked when bundle configuration changed.
	 */
	@Override
	public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
		ServiceRegistration newChangeServiceHook = null;
		ServiceRegistration newGetServiceHook = null;
		
		try {
			setConfiguration(properties);
			
			changeServiceHook = new ChangeServiceHook(hostIP, databaseProxy);
			getServiceHook = new GetServiceHook(databaseProxy);
			
			newChangeServiceHook = context.registerService(EventListenerHook.class.getName(), changeServiceHook, null);
			newGetServiceHook = context.registerService(FindHook.class.getName(), getServiceHook, null);
			
			logger.log(LogService.LOG_INFO, "EventListenerHook has been registered");
			logger.log(LogService.LOG_INFO, "FindHook has been registered");
		} finally {
			if (newChangeServiceHook != null) {
				ServiceRegistration oldRegistration = changeServiceHookReference.getAndSet(newChangeServiceHook);
				if (oldRegistration != null) {
					oldRegistration.unregister();
				}
			}
			
			if (newGetServiceHook != null) {
				ServiceRegistration oldRegistration = getServiceHookReference.getAndSet(newGetServiceHook);
				if (oldRegistration != null) {
					oldRegistration.unregister();
				}
			}
		}
	}

	private void setConfiguration(Dictionary<String, ?> properties) throws ConfigurationException {
		if (properties == null) {
			try {
				hostIP = InetAddress.getLocalHost().getHostAddress();
			} catch (UnknownHostException e) {
				logger.log(LogService.LOG_ERROR, "Unknown host", e);
			}
		} else {
			hostIP = (String) properties.get(PROP_HOST);
			if (hostIP == null) {
				throw new ConfigurationException(PROP_HOST, "Mandatory field");
			}
		}
		
		logger.log(LogService.LOG_INFO, "Host ip set to " + hostIP);
	}
}
